iT邦幫忙

2025 iThome 鐵人賽

DAY 9
0

內文

Day 8,我們模擬了「完全沒有 Session」的極端情境,但這個情境又回到過去的老路:

  • 使用者每次都要傳帳密,效能差、不安全。
  • 即便改成隨機字串 Token,仍然無法攜帶額外資訊,也不能安全控制失效。

到了現在,工程師需要一種更聰明的解法,而且包含以下優點:

  • 無狀態(伺服器不用記住 Session)。
  • 自帶資訊(角色、權限、到期時間)。
  • 防止竄改(不能隨便改內容)。

於是, JWT(JSON Web Token) 登場了。

JWT 是什麼?

JWT 是一種開放標準(RFC 7519),它的設計理念是:

把使用者資訊編碼成一個 Token,並透過簽名驗證真偽。

這樣一來:

  • 使用者登入成功後,伺服器回傳一個 JWT。
  • 使用者之後的請求只要帶上 JWT,伺服器就能驗證並認出他。
  • 不需要查詢 Session,不需要共用記憶體,任何一台伺服器都能驗證。

JWT 的結構

不免俗的,叫紹到JWT就需要介紹他的結構,一個典型的 JWT 長這樣:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkVyaWMiLCJyb2xlIjoiVVNFUiIsImlhdCI6MTUxNjIzOTAyMn0.
TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

它由三個部分組成,用「.」分隔:

  1. Header(頭部)

    • 說明演算法與 Token 類型。

    • 例如:

      {
        "alg": "HS256",
        "typ": "JWT"
      }
      
  2. Payload(負載)

    • 存放使用者相關的資訊。

    • 例如:

      {
        "sub": "1234567890",
        "name": "Eric",
        "role": "USER",
        "iat": 1516239022,
        "exp": 1516242622
      }
      
    • 常見欄位:

      • sub → 使用者 ID
      • role → 使用者角色
      • iat → 發行時間 (Issued At)
      • exp → 過期時間 (Expire Time)
  3. Signature(簽名)

    • 由 Header + Payload + Secret 產生,用來驗證 Token 是否被竄改。

    • 計算方式:

      HMACSHA256(
        base64UrlEncode(header) + "." + base64UrlEncode(payload),
        secret
      )
      

只要 Payload 被竄改,簽名就會對不上,伺服器立刻能檢查出來。

駭客一來幾乎沒有辦法拿到解碼的Secret,因此不能去修改內容來擴增自己的權限。

有了JWT,密碼就變得更加安全有保障。

在前幾天,我們有說到Token有一個問題,那就是沒有辦法主動失效的問題,JWT雖然解決了Token,但仍然是一種Token,所以仍然沒有辦法主動失效,這點想要特別點出來讓大家理解。

到期時間 (Expire Time) vs 主動失效 (Invalidate)

我自己在接觸到JWT的時候就有遇到這個問題

1. 到期時間 (exp)

JWT 本身可以設定一個到期時間,超過時間後,伺服器會自動拒絕它。

  • 優點:簡單、無需額外儲存。
  • 缺點:這是「被動」的失效 ,因為 Token 在時間到之前,依然有效。

2. 主動失效(Invalidate)

有些情境需要 立即收回 Token,例如:

  • 使用者按下「登出」。
  • 管理員封鎖帳號。
  • 使用者更改密碼,但駭客手上仍握有舊的 JWT。

問題在於:

JWT 發出去之後,伺服器無法「主動收回」它,因為 JWT 是 Stateless,不存在伺服器的記憶體。

3. 解決方案

實務上會搭配以下機制:

  • 黑名單 (Blacklist)
    • 使用者登出時,把該 Token 記錄到黑名單。
    • 驗證時先檢查黑名單,如果存在就拒絕。
  • Refresh Token
    • Access Token(JWT)設計成很短命(例如 15 分鐘)。
    • Refresh Token 存在資料庫,可以決定是否再發新的 Access Token。
    • 如果帳號被封鎖 → Refresh Token 失效,舊的 JWT 自然無法續命。
  • Token Rotation(輪替)
    • 每次刷新 Access Token 時,Refresh Token 也更新。
    • 舊的 Refresh Token 立刻失效,防止被重複使用。

回顧一下今天學到的東西,我們可以知道JWT的出現跟他想要解決的問題,讓我們整理成以下的重點:

JWT 解決了什麼?

  1. 自帶資訊 → 不只是隨機字串,而是攜帶了使用者 ID、角色、過期時間。
  2. 無狀態 → 伺服器不用保存 Session,任何節點都能驗證。
  3. 防竄改 → 簽名確保內容不能隨意修改。

JWT 的限制

  1. 無法主動失效 → 必須搭配黑名單或 Refresh Token。
  2. 不能放敏感資訊 → Payload 是 Base64 編碼,不是加密。
  3. Token 較長 → 比單純 Session ID 更大,會增加請求流量。

總結

今天我們完整認識了 JWT 的結構

  • Header:描述演算法與類型。
  • Payload:自帶使用者資訊(角色、權限、到期時間)。
  • Signature:保證不被竄改。

我們也釐清了:

  • JWT 的 到期時間 是「被動失效」。
  • 若要「主動失效」,必須額外設計 黑名單、Refresh Token、Rotation

這就是 JWT 的強大之處:無狀態、自帶資訊、防竄改,同時也是它的限制所在。

明天(Day 10),我們將實際用 Java 原生程式碼來手動實作一個簡單的 JWT:

  • 使用 Base64 編碼。
  • 使用 HMAC-SHA256 產生簽名。
  • 從零開始打造,幫助大家真正理解「簽名是怎麼來的」。

大家明天見!


上一篇
Day 8 無狀態請求與自帶資訊的認證方式
下一篇
Day 10 Java 手動實作 JWT
系列文
「站住 口令 誰」關於資安權限與授權的觀念教學,以Spring boot Security框架實作11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言